Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: TipKit rule triggers an empty_count violation #5918

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Ueeek
Copy link
Contributor

@Ueeek Ueeek commented Dec 28, 2024

resolve #5883
Skip TipKit RuleMacro in EmptyCountRule

@Ueeek Ueeek marked this pull request as draft December 28, 2024 05:40
@Ueeek Ueeek force-pushed the bug/skipTipKitRuleMacroInEmptyCountRule branch from e0df3d7 to e69e152 Compare December 28, 2024 05:49
@SwiftLintBot
Copy link

SwiftLintBot commented Dec 28, 2024

18 Messages
📖 Building this branch resulted in a binary size of 24893.18 KiB vs 24892.7 KiB when built on main (0% larger).
📖 Linting Aerial with this PR took 0.93 s vs 0.93 s on main (0% slower).
📖 Linting Alamofire with this PR took 1.27 s vs 1.29 s on main (1% faster).
📖 Linting Brave with this PR took 8.47 s vs 8.5 s on main (0% faster).
📖 Linting DuckDuckGo with this PR took 5.51 s vs 5.51 s on main (0% slower).
📖 Linting Firefox with this PR took 11.07 s vs 11.06 s on main (0% slower).
📖 Linting Kickstarter with this PR took 10.33 s vs 10.34 s on main (0% faster).
📖 Linting Moya with this PR took 0.53 s vs 0.54 s on main (1% faster).
📖 Linting NetNewsWire with this PR took 2.94 s vs 2.95 s on main (0% faster).
📖 Linting Nimble with this PR took 0.79 s vs 0.79 s on main (0% slower).
📖 Linting PocketCasts with this PR took 8.68 s vs 8.78 s on main (1% faster).
📖 Linting Quick with this PR took 0.46 s vs 0.45 s on main (2% slower).
📖 Linting Realm with this PR took 4.52 s vs 4.5 s on main (0% slower).
📖 Linting Sourcery with this PR took 2.33 s vs 2.33 s on main (0% slower).
📖 Linting Swift with this PR took 4.55 s vs 4.54 s on main (0% slower).
📖 Linting VLC with this PR took 1.23 s vs 1.23 s on main (0% slower).
📖 Linting Wire with this PR took 18.32 s vs 18.3 s on main (0% slower).
📖 Linting WordPress with this PR took 11.49 s vs 11.53 s on main (0% faster).

Generated by 🚫 Danger

@Ueeek Ueeek marked this pull request as ready for review December 28, 2024 05:49
Copy link
Collaborator

@SimplyDanny SimplyDanny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Looks good in general, yet we can be even more restrictive in the check for the #Rule macro.

@@ -62,6 +64,8 @@ struct EmptyCountRule: Rule {
Example("isEmpty && [Int]().isEmpty"),
Example("[Int]().count != 3 && [Int]().↓count != 0 || ↓count == 0 && [Int]().count > 2"):
Example("[Int]().count != 3 && ![Int]().isEmpty || isEmpty && [Int]().count > 2"),
Example("let predicate = #Predicate<SwiftDataModel> { $0.list.↓count == 0 }"):
Example("let predicate = #Predicate<SwiftDataModel> { $0.list.isEmpty }"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of #Predicate<SwiftDataModel> you may also use any other (simpler) macro that's not #Rule.

Copy link
Contributor Author

@Ueeek Ueeek Jan 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion!
I used "#ExampleMacro" as an example of Macro, referring NoMagicNumberRule.
Or, is it better to use an actual example?(e.g. #Preview?) 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#ExampleMacro is great. The only reason I was suggesting another name is to keep the examples very simple and reduced down to the significant aspects. Otherwise, the name or its actual existence is not important as long as it's something different than #Rule to have a valid test case.

What comes to my mind now is that we should also test against #Rule without any arguments or more than one, the macro with a non-trailing closure, a return statement inside or more than one statement, ...

You can exclude these test cases from appearing in the documentation for simplicity by adding the argument excludeFromDocumentation: true. Only leave the ones you have now and skip the others as they are not helping users in understanding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice suggestion, let me add the following tests.

  • #Rule without any arguments
  • #Rule with more than 1 argument
  • #Rule with non-trailing closure
  • #Rule with multiple trailing closure
  • #Rule with a closure with the return statement
  • #Rule with a closure with multiple statements.

So far, writing the code of the above test cases with the #Rule macro from the Tips Kit results in a compile error.
However, we added the tests for the following reasons. Do I understand correctly? 🤔

  • To cover all the conditional branches introduced in this PR.
  • To prepare for the possibility that the #Rule macro might support {no/multiple} {arguments/closures} in the future.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we want to make very sure that the rule only ignores the TipKit #Rule macro, not any other #Rule macro. To know for sure, the rule would need full type information. That's expensive, so we try to encode all the syntactic details we know about the macro in order to reduce false positives. That's not 100% even now, but close enough.

The compiler complains about these cases for TipKit's #Rule macro. There could be other #Rule macros which are not as strict. We still want to check them.

If you remove import TipKit and define your own #Rule macro, the compiler will be happy. That's what you need to imagining as a test setup (without specifying that explicitly).

Makes sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Thank you for explain it! I'm learning lot from you. 😄

@SimplyDanny
Copy link
Collaborator

Please rebase your branch to resolve the conflict.

@Ueeek Ueeek force-pushed the bug/skipTipKitRuleMacroInEmptyCountRule branch from c63fa72 to a18f2a4 Compare January 6, 2025 12:35
@Ueeek Ueeek force-pushed the bug/skipTipKitRuleMacroInEmptyCountRule branch from a18f2a4 to 3b51ccc Compare January 6, 2025 14:32
doSomething()
return $0.donations.isEmpty
}
"""),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To verify the correction mechanism, one test case is enough. We don't need to repeat all of them here again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Event-based TipKit rule triggers an empty_count violation
3 participants